Skip to content

feat: add OpenAI Codex CLI backend#48

Merged
Cannon07 merged 4 commits intomainfrom
feat/codex-cli-backend
May 1, 2026
Merged

feat: add OpenAI Codex CLI backend#48
Cannon07 merged 4 commits intomainfrom
feat/codex-cli-backend

Conversation

@Cannon07
Copy link
Copy Markdown
Owner

@Cannon07 Cannon07 commented May 1, 2026

Summary

  • Adds OpenAI Codex CLI as the fourth supported AI backend alongside Claude Code, OpenCode, and Copilot CLI.
  • Install writes .codex/hooks.json and detects the required codex_hooks = true feature flag in .codex/config.toml (project or global) — :CodePreviewStatus and :checkhealth both surface flag state so users can self-diagnose silent-no-op failures.
  • Adds shell-write detection to the unified Bash hook: > / >> / &> / &>>, mv X.tmp X, cp, tee, and sed -i targets are flagged in the changes registry as bash_modified / bash_created so users get neo-tree feedback for shell-driven edits — important for Codex GPT models, which prefer the atomic-replace idiom ({ printf …; cat F; } > F.tmp && mv F.tmp F).
  • Fixes ApplyPatch *** Delete File: showing the orange "modified" pencil instead of the red "deleted" trash icon.

What's included

Codex backend

  • backends/codex/{code-preview-diff,code-close-diff}.sh — translate Codex's payload (which delivers apply_patch text in tool_input.command) into the normalized shape consumed by bin/core-{pre,post}-tool.sh. Bash passes through.
  • lua/code-preview/backends/codex.lua — install/uninstall, plus feature_flag_state() that checks .codex/config.toml (project) and falls back to ~/.codex/config.toml (global).
  • :CodePreviewInstall/UninstallCodexCliHooks commands; Codex rows in :CodePreviewStatus and :checkhealth, including feature-flag detection.

Shell-write detection (Bash hook)

  • New block in bin/core-pre-tool.sh that extracts likely write targets from a Bash command and marks each one bash_modified (file exists) or bash_created (file doesn't exist) in the changes registry.
  • looks_like_path filters false positives leaked from quoted strings (e.g. printf '<!-- … -->\n\n'); is_transient_path skips .tmp/.bak/.swp//dev/*//tmp/*; tilde paths expand to $HOME before the relative-path resolver to avoid $CWD/~/foo.
  • rm-wins reveal precedence — when a command both rms and writes, only the rm branch queues a defer_fn reveal so we don't double-fire.
  • Acknowledged limitations (in-code comments): mv -t DST flag-inverted form, tee FILE OTHER_FILE multi-target, and the always-on cost of the detector for read-only Bash invocations.

Neo-tree integration for shell writes

  • bash_modified and bash_created render with the same icons/highlights as modified and created for v1 — documented in neo_tree.lua as a deliberate simplification.
  • New changes.clear_by_statuses({...}) helper; the Bash post-hook now batches deleted + bash_modified + bash_created cleanup into a single RPC instead of three.

ApplyPatch delete fix

  • show_diff accepts an optional action hint; the Codex/ApplyPatch hook passes "delete" for *** Delete File: directives. mark_change_and_reveal only emits "deleted" when explicitly told — a legitimate truncate-to-empty edit still shows as modified.
  • vim.loop.fs_stat switched to vim.uv.fs_stat in diff.lua to match the convention used elsewhere in the codebase.

Docs / housekeeping

  • README: Codex Quick Start section, backend list updated to all four, Neovim floor aligned to >= 0.10 (matches actual vim.uv usage), :checkhealth wording, test-runner examples for backends/copilot and backends/codex.
  • .gitignore: ignore test_output.log.

Tests

22 new shell tests in the Codex suite plus 2 plenary regressions:

  • tests/backends/codex/test_install.sh.codex/hooks.json layout, idempotent re-install, user-authored Pre/PostToolUse entries survive install/uninstall, feature-flag detection (project + global, missing flag, no config.toml).
  • tests/backends/codex/test_edit.sh — Codex apply_patch translation, Bash rm, shell-write detection (modified/created/atomic-replace/.tmp filter), HTML-comment false-positive guard, read-only no-op, noise-tool skip, malformed-payload skip.
  • tests/backends/codex/test_apply_patch.sh — Update / Add / mixed Update+Add+Delete.
  • tests/plugin/diff_lifecycle_spec.luashow_diff(..., "delete") marks the file deleted; truncate-to-empty without an action stays modified (regression guard against the false-positive that the action hint replaced).
  • test_install_preserves_user_hooks extended to assert PostToolUse mirroring (was previously only checking PreToolUse).

Test plan

  • bash tests/run.sh all passes locally
  • ./tests/run_lua.sh diff_lifecycle — plenary regressions pass
  • Install/uninstall cycle in a real Codex CLI session, with and without codex_hooks = true
  • :CodePreviewStatus and :checkhealth code-preview correctly report flag state for: project config, global config (~/.codex/config.toml), missing flag, no config file
  • Codex apply_patch Update / Add / Delete — diffs open on pre, close on accept, *** Delete File: shows the red trash icon in neo-tree
  • Codex Bash atomic-replace ({ … } > F.tmp && mv F.tmp F) — neo-tree shows the orange pencil on F during the approval window, clears on post

Cannon07 and others added 4 commits May 1, 2026 21:29
Adds Codex CLI as the fourth supported backend, plus shell-write
detection in the Bash hook (motivated by Codex GPT models' atomic-
replace idiom) and an ApplyPatch delete-icon fix that surfaced while
testing Codex's `*** Delete File:` directives.

- Codex backend: `.codex/hooks.json` install + `codex_hooks` feature-
  flag detection (project + global), surfaced in :CodePreviewStatus
  and :checkhealth.
- Shell-write detection: `>` / `>>` / `&>` / `&>>`, `mv X.tmp X`, `cp`,
  `tee`, `sed -i` targets are flagged in the changes registry as
  bash_modified / bash_created so neo-tree shows feedback for shell-
  driven edits during the approval window.
- ApplyPatch delete: show_diff accepts an action hint; deletes now
  render the red trash icon, with no false positives for legitimate
  truncate-to-empty edits.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The blanket /tmp/* rule masked real shell-write targets on Linux,
where mktemp paths stay under /tmp (macOS resolves /tmp to /private/tmp
via pwd -P, so the filter happened to miss). Transience is signaled by
the extension or /dev/*, not by being under /tmp.

Fixes Ubuntu CI failures in tests/backends/codex/test_edit.sh:
- Codex Bash shell write marks existing file modified
- Codex Bash atomic-replace idiom marks real target
- Codex Bash shell write marks new file created
- Codex Bash filters HTML-comment false positives

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Without `approval_policy = "on-request"` and `sandbox_mode = "read-only"`
in config.toml, Codex applies edits without prompting and the diff
preview never blocks on the user's decision — defeating the point of
the workflow. Bundle both alongside the existing `codex_hooks` flag
in the Quick Start.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Cannon07 Cannon07 merged commit 89a6937 into main May 1, 2026
2 checks passed
@Cannon07 Cannon07 deleted the feat/codex-cli-backend branch May 1, 2026 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant